using static FotoLab.DomainLayer.Model.Medewerker;
using EfEnumToLookup.LookupGenerator;

namespace FotoLab.DomainLayer
{
    using System;
    using System.Data.Entity;
    using System.Linq;
    using System.Threading.Tasks;
    using FotoLab.DomainLayer.Model;
    using Helper;
    using Microsoft.AspNet.Identity;

    public class DomainContext 
        : DbContext, 
          IUserStore<Gebruiker>, 
          IUserLockoutStore<Gebruiker, string>, 
          IUserTwoFactorStore<Gebruiker, string>
    {
        // Your context has been configured to use a 'DomainContext' connection string from your application's 
        // configuration file (App.config or Web.config). By default, this connection string targets the 
        // 'FotoLab.DomainLayer.DomainContext' database on your LocalDb instance. 
        // 
        // If you wish to target a different database and/or database provider, modify the 'DomainContext' 
        // connection string in the application configuration file.
        public DomainContext()
            : base("name=DomainContext")
        {
        }

        public static DomainContext Create()
        {
            return new DomainContext();
        }

        // Add a DbSet for each entity type that you want to include in your model. For more information 
        // on configuring and using a Code First model, see http://go.microsoft.com/fwlink/?LinkId=390109.

        public virtual DbSet<Foto> Fotos { get; set; }
        public virtual DbSet<Upload> Uploads { get; set; }
        public virtual DbSet<Fotograaf> Fotografen { get; set; }
        public virtual DbSet<Adres> Adressen { get; set; }
        public virtual DbSet<Klant> Klanten { get; set; }
        public virtual DbSet<Order> Orders { get; set; }
        public virtual DbSet<Product> Producten { get; set; }
        public virtual DbSet<Orderregel> Orderregels { get; set; }
        public virtual DbSet<Gezicht> Gezichten { get; set; }
        public virtual DbSet<Medewerker> Medewerkers { get; set; }

        // Oplossing vanaf http://stackoverflow.com/a/10904877
        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            modelBuilder.ComplexType<LoginCode>()
                        .Property(c => c.Code)
                        .HasColumnName("LoginCode");

            modelBuilder.ComplexType<Naam>()
                        .Property(n => n.Aanhef)
                        .HasColumnName("Aanhef");

            modelBuilder.ComplexType<Naam>()
                        .Property(n => n.Voornaam)
                        .HasColumnName("Voornaam");

            modelBuilder.ComplexType<Naam>()
                        .Property(n => n.Tussenvoegsel)
                        .HasColumnName("Tussenvoegsel");

            modelBuilder.ComplexType<Naam>()
                        .Property(n => n.Achternaam)
                        .HasColumnName("Achternaam");

            modelBuilder.Entity<Adres>()
                        .Property(a => a.Postcode)
                        .HasMaxLength(6);

            modelBuilder.Entity<Adres>()
                        .Property(a => a.Huisnummer)
                        .HasMaxLength(15);

            modelBuilder.Entity<Adres>()
                        .HasKey(a => new { a.Postcode, a.Huisnummer });

            modelBuilder.Entity<Adres>()
                        .ToTable("Adressen");

            modelBuilder.Entity<Foto>()
                        .ToTable("Fotos");

            modelBuilder.Entity<Foto>()
                        .HasMany(f => f.Gezichten)
                        .WithMany(g => g.Fotos)
                        .Map(x => x.ToTable("GezichtOpFoto"));

            modelBuilder.Entity<Fotograaf>()
                        .ToTable("Fotografen");

            modelBuilder.Entity<Gezicht>()
                        .ToTable("Gezichten");

            modelBuilder.Entity<Klant>()
                        .ToTable("Klanten");

            modelBuilder.Entity<Order>()
                        .ToTable("Orders");

            modelBuilder.Entity<Orderregel>()
                        .ToTable("OrderRegels");

            modelBuilder.Entity<Product>()
                        .ToTable("Producten");

            modelBuilder.Entity<Medewerker>()
                        .ToTable("Medewerkers");

            base.OnModelCreating(modelBuilder);
        }

        #region IUserStore
        Task<Gebruiker> IUserStore<Gebruiker, string>.FindByIdAsync(string userId)
        {
            return Task.Run(() => {
                var guid = Guid.Parse(userId);
                Gebruiker result = null;

                result = Fotografen.Find(guid);
                if (result == null)
                {
                    result = Medewerkers.Find(guid);
                }

                return result;
            });
        }

        Task<Gebruiker> IUserStore<Gebruiker, string>.FindByNameAsync(string userName)
        {
            return Task.Run(() =>
            {
                Gebruiker result = null;

                result = Fotografen.FirstOrDefault(g => g.GebruikersNaam == userName);
                if (result == null)
                {
                    result = Medewerkers.FirstOrDefault(g => g.GebruikersNaam == userName);
                }

                return result;
            });
        }
        #endregion

        #region IUserStore Unused Methods
        Task IUserStore<Gebruiker, string>.CreateAsync(Gebruiker user)
        {
            throw new NotImplementedException();
        }

        Task IUserStore<Gebruiker, string>.UpdateAsync(Gebruiker user)
        {
            throw new NotImplementedException();
        }

        Task IUserStore<Gebruiker, string>.DeleteAsync(Gebruiker user)
        {
            throw new NotImplementedException();
        }
        #endregion

        #region IUserLockOutStore Unused Methods
        Task<DateTimeOffset> IUserLockoutStore<Gebruiker, string>.GetLockoutEndDateAsync(Gebruiker user)
        {
            throw new NotImplementedException();
        }

        Task IUserLockoutStore<Gebruiker, string>.SetLockoutEndDateAsync(Gebruiker user, DateTimeOffset lockoutEnd)
        {
            throw new NotImplementedException();
        }

        Task<int> IUserLockoutStore<Gebruiker, string>.IncrementAccessFailedCountAsync(Gebruiker user)
        {
            throw new NotImplementedException();
        }

        Task IUserLockoutStore<Gebruiker, string>.ResetAccessFailedCountAsync(Gebruiker user)
        {
            throw new NotImplementedException();
        }

        Task<int> IUserLockoutStore<Gebruiker, string>.GetAccessFailedCountAsync(Gebruiker user)
        {
            return Task.FromResult(0);
        }

        Task<bool> IUserLockoutStore<Gebruiker, string>.GetLockoutEnabledAsync(Gebruiker user)
        {
            return Task.FromResult(false);
        }

        Task IUserLockoutStore<Gebruiker, string>.SetLockoutEnabledAsync(Gebruiker user, bool enabled)
        {
            throw new NotImplementedException();
        }
        #endregion

        #region IUserTwoFactorStore Unused Methods
        Task IUserTwoFactorStore<Gebruiker, string>.SetTwoFactorEnabledAsync(Gebruiker user, bool enabled)
        {
            throw new NotImplementedException();
        }

        Task<bool> IUserTwoFactorStore<Gebruiker, string>.GetTwoFactorEnabledAsync(Gebruiker user)
        {
            return Task.FromResult(false);
        }
        #endregion
    }
}